package com.rpc.demo.consumer.handler;

import com.rpc.demo.common.model.Invocation;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * @Author: ZhaoJie
 * @Date: 2022/3/29
 * @Description :
 * @Modify :
 * ===================================================
 * Modifier        Modifytime        Description
 * ===================================================
 */
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {

    private static ChannelHandlerContext context;//上下文
    private static Object result; //返回的结果
    private static Invocation invocation; //客户端调用方法时，传入的参数


    //与服务器的连接创建后，就会被调用, 这个方法是第一个被调用(1)
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(" channelActive 被调用  ");
        context = ctx; //因为我们在其它方法会使用到 ctx
    }

    //收到服务器的数据后，调用方法 (4)
    //
    @Override
    public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(" channelRead 被调用  ");
        result = msg;
        notify(); //唤醒等待的线程
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }

    //被代理对象调用, 发送数据给服务器，-> wait -> 等待被唤醒(channelRead) -> 返回结果 (3)-》5
    @Override
    public synchronized Object call() throws Exception {
        System.out.println(" call1 被调用  ");
        Map<String, String> map = new HashMap<>();
        map.put("sss", "sss");
        context.writeAndFlush(invocation);
        //进行wait
        wait(); //等待channelRead 方法获取到服务器的结果后，唤醒
        System.out.println(" call2 被调用  ");
        return  result; //服务方返回的结果

    }
    //(2)
    public void setPara(Object[] args, String className, String methodName, Class[] parameterTypes) {
        System.out.println(" setPara  ");
        this.invocation = new Invocation();
        this.invocation.setInterfaceName(className);
        this.invocation.setMethodName(methodName);
        this.invocation.setParamTypes(parameterTypes);
        this.invocation.setParams(args);

    }
}

